﻿using System.Collections.Generic;
using System.Linq;
using System.Windows;
using DeepZoomPivotConstructor.DTBuilderLib;
using DeepZoomSLUtilities.HotSpots.Specific;

namespace DeepZoomSLUtilities.HotSpots
{
    /// <summary>
    /// Base class for a hot spot - geometrical area. It contains actions
    /// that actually do the work (to hopefully save memory and search time.
    /// </summary>
    public class HotSpotInfo
    {
        /// <summary>
        /// The sub image that this hot spot info is associated with
        /// </summary>
        internal SubImageHotSpotInfo SubImage { get; set; }

        /// <summary>
        /// The main control - used so the hot spot can get access directly to the control
        /// and manipulate the display as required.
        /// </summary>
        public static DeepZoomer ZoomControl { get; set; }

        /// <summary>
        /// What is our boundry, in local sub-image coordinates
        /// </summary>
        protected Rect boundary;

        /// <summary>
        /// Gets the boundary of this HS in sub-image coordinates
        /// </summary>
        public Rect Boundary
        {
            get { return boundary; }
        }

        protected List<HotSpotActionBase> Actions { get; set; }

        /// <summary>
        /// Init with the meta data for the hot spot. We expect the
        /// coordinates to be in sub-image local coordinates!
        /// </summary>
        /// <param name="meta"></param>
        public HotSpotInfo(DZHotSpotMetaData meta)
        {
            boundary = new Rect(meta.LinkLocation.X,
                meta.LinkLocation.Y,
                meta.LinkLocation.Width,
                meta.LinkLocation.Height);
            ZIndex = meta.LinkLocation.Z;

            Actions = HotSpotInfoFactory.CreateHSActions(this, meta.Actions);

            ///
            /// Now, do some quick summarizing so we can do some checks up the line more
            /// efficiently.
            /// 

            clickToActivate = (from a in Actions where a.LeftClickToActivate select a).FirstOrDefault() != null;

            keysToActivate = Actions.Aggregate((int)0, (keysActive, a) => keysActive | a.KeyToActivate);
        }

        /// <summary>
        /// The z index of this hot spot. Higher is more near the front
        /// </summary>
        public int ZIndex { get; private set; }

        /// <summary>
        /// True if this hot spot responds to a left click.
        /// </summary>
        private bool clickToActivate { get; set; }

        /// <summary>
        /// Cache the OR of all keys that we know about that can activate us
        /// </summary>
        private int keysToActivate { get; set; }

        /// <summary>
        /// Is the given point inside the rect that represents our hot spot?
        /// </summary>
        /// <param name="msiSubImageLocalPoint">A point in sub-image local coordinates</param>
        /// <returns></returns>
        internal bool ContainsPoint(Point msiSubImageLocalPoint)
        {
            return boundary.Contains(msiSubImageLocalPoint);
        }

        /// <summary>
        /// The mouse buttons we can press...
        /// </summary>
        public enum MouseButtons
        {
            LeftButton
        }

        /// <summary>
        /// The hot spot has been clicked. The default method does nothing
        /// </summary>
        internal bool ActivatedByMouseClick(MouseButtons what)
        {
            return clickToActivate;
        }

        /// <summary>
        /// Returns true if a given key will activate this guy
        /// </summary>
        /// <param name="aKey"></param>
        /// <returns></returns>
        internal bool ActivatedByKeyPress(DZHotSpotMetaData.ActionData.KeyPressed aKey)
        {
            return (keysToActivate & ((int)aKey)) != 0;
        }

        /// <summary>
        /// Actually run the dude!
        /// </summary>
        /// <param name="what"></param>
        internal void Execute(MouseButtons what)
        {
            var actions = from a in Actions
                          where a.LeftClickToActivate
                          select a;
            foreach (var a in actions)
            {
                a.Execute();
            }
        }

        /// <summary>
        /// Run the dude if a key was pressed!
        /// </summary>
        /// <param name="akey"></param>
        internal void Execute(DZHotSpotMetaData.ActionData.KeyPressed akey)
        {
            var actions = from a in Actions
                          where (a.KeyToActivate & ((int)akey)) != 0
                          select a;
            foreach (var a in actions)
            {
                a.Execute();
            }
        }

        /// <summary>
        /// Is there a left click mouse dude that is a centering guy?
        /// </summary>
        /// <returns></returns>
        internal bool HasMouseCentering()
        {
            return Actions.Where(a => a.LeftClickToActivate && a is HotSpots.Specific.HSCenter).Any();
        }
    }
}
